﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using Crusades.Extensions;
using Crusades.Geometry;
using Crusades.Helpers;

namespace Crusades.Arrows {

  public partial class Arrow {
    private static int objectCounter;
    private int objectID;

    private List<Path> paths = new List<Path>();
    private int ObjectID {
      get {
        if (objectID == 0) {
          objectID = objectCounter++;
        }
        return objectID;
      }
    }
    public static readonly DependencyProperty PercentFilledProperty
    = DependencyProperty.Register("PercentFilled", typeof(double), typeof(Arrow),
                                  new PropertyMetadata(0.0, PercentFilledChangedCallback));
    private BezierArrowSegment segment;
    private Point StartPoint{ get; set;}

    private static void PercentFilledChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) {
      Arrow arrow = (Arrow)d;
      arrow.RenderTo((double)e.NewValue);
    }

    public double PercentFilled {
      get { return (double)GetValue(PercentFilledProperty); }
      set { SetValue(PercentFilledProperty, value); }
    }

    public double Thickness { get; set; }
    public Brush Color { get; set; }
    
    public double ArrowheadThickness { get; set; }

    public Arrow() {
      InitializeComponent();
      objectID++;
    }

    public void RenderTo(double t){
      if(segment==null)return;
      PathBuilder pathBuilder = new PathBuilder(StartPoint, Color, Thickness);

      LayoutRoot.Children.Clear();
      Path bPath = segment.RenderTo(pathBuilder, t);
      paths.Add(bPath);
      addArrowhead(segment.FinalVector.PointA, segment.FinalVector.PointB, ArrowheadThickness); 
      foreach (var path in paths){
        LayoutRoot.Children.Add(path);
      }
      paths.Clear();
    }
    public void AddBezierSegment(Vector[] ControlPoints) {
      if(StartPoint.Equals(new Point(0,0))){
        StartPoint = ControlPoints[0].toPoint();
      }
      segment = new BezierArrowSegment(ControlPoints);
      
    }

    private void addArrowhead(Vector p2, Vector p3, double arrowheadSize) {
      PathBuilder builder = new PathBuilder(p3.toPoint(), Color, Thickness);
      Point anchor = p3.toPoint();
      Point left = new Point(anchor.X - 3 * arrowheadSize, anchor.Y);
      Point top = new Point(anchor.X, anchor.Y + 3 * arrowheadSize);
      Point right = new Point(anchor.X + 3 * arrowheadSize, anchor.Y);
      builder.AddLineSegment(left);
      builder.AddLineSegment(top);
      builder.AddLineSegment(right);
      Path path = builder.AddLineSegment(anchor);
      path.Fill = Color;
      path.Name = "ArrowHead" + ObjectID;
      double degrees = findAngle(p3, p2);
      RotateTransform transform = new RotateTransform { Angle = degrees, CenterX = anchor.X, CenterY = anchor.Y };
      path.RenderTransform = transform;
      paths.Add(path);
    }

    private double findAngle(Vector p3, Vector p2) {
      double tan = (p3.Y - p2.Y) / (p3.X - p2.X);
      double theta = Math.Atan(tan);
      theta += Math.PI / 2;
      if (p2.X < p3.X) {
        theta += Math.PI;
      }
      return theta.Degrees();
    }
  }
}
